

                     L                ZZZZZZ         RRRRR           SSSSS
                     L                    Z          R    R         S
                     L          aaa      Z      aaa  R    R  u   u  S
                     L            a     Z         a  RRRRR   u   u  SSSSS
               XX    L         aaaa    Z       aaaa  R    R  u   u       S
              XXXX   L        a   a   Z       a   a  R    R  u   u       S
             XXXXXX  LLLLLLL  aaaaa  ZZZZZZZ  aaaaa  R    R  uuuuu  SSSSSS
             XXXXXX       
        XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
       XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
        XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
             XXXXXX
             XXXXXX
              XXXX        proudly presents his 6.Cracking Tutorial (04.04.1999)
               XX                          Start Clean 1.2

I.    Tools you need for my tutorial
II.   Cracking with a Disassembler (W32Dasm)
III.  Cracking with Debugger (W32Dasm or Soft Ice)
III.1 Installing Soft-Ice
III.2 Let's start cracking
IV.   Writing a patch in C++
V.    Writing a Key Generator in C++
VI.   BTW

I    Tools you need for my tutorial
     Win32Dasm 8.9  (get at http://Qserve.8m.com)
     (perhaps) Soft-Ice for Windows (get at http://Qserve.8m.com)
     A hex-editor, I prefer Hex Workshop 2.54 (get at www.bpsoft.com, change bytes 909A and 
                                               256B4 to 85; then you can register it with every
                                               serial#)
     Jaylock, the program to be cracked (mail me if you don't find it)
     Get a Windows-API reference. (Included in any Borland/Inprise programming languages)
     
II.  Cracking with Win32Dasm:

     This tutorial is (slightly) based on one of Quapla. This was one of the first tutorials I
     was able to understand. Greetings to you :)

     At first (as every time you crack something) we look at the target carefully. It seems that
     the only difference between the registered and the unregistered version is the nag-screen
     and the string "Shareware version" in the main window. We will later see that this is indeed
     everything. In the nag-screen is a button that makes a "Enter serial" window appear.
     So let's start cracking. To get rid of a nag-screen I usually do this: (+ORC would start
     crying if he reads that, because it is absolutely no ZEN cracking, but more I-DONT-WANT-TO-
     USE-MY-BRAIN-BRUTE-FORCE cracking). If you can't find a string appearing in the nag-screen
     in W32Dasm, start the program in W32Dasm debug mode and choose "Auto step over". Do this 
     until the nag-screen appears. W32Dasm will stop at a CALL. Now breakpoint on this call (pay
     attention W32Dasm deletes the breakpoints when you start a new debug session) and enter it
     when it is reached trace into that call and choose "Auto step over" again until you come to
     the next call. Look if there's a conditional jump near before that call that leads beyond
     the call. Look what happens if you change the condition of the jump je->jne, jl->jb... If
     the nag-screen disappeared you got it, if the programm didn't start you have to trace into
     the call again and keep on doing this until you find the right conditional jump.
     For Start Clean you should see this after you did my method a few times:

     |:00401D9A   
     |
     :00401EA0 8B442404                mov eax, dword ptr [esp+04]
     :00401EA4 A348724000              mov dword ptr [00407248], eax

     * Reference To: COMCTL32.InitCommonControls, Ord:0011h
                                       |
     :00401EA9 FF1508924000            Call dword ptr [00409208]
     :00401EAF E84CF1FFFF              call 00401000
     :00401EB4 A34C724000              mov dword ptr [0040724C], eax
     :00401EB9 85C0                    test eax, eax
     :00401EBB 7524                    jne 00401EE1
     :00401EBD 6A00                    push 00000000
     :00401EBF A148724000              mov eax, dword ptr [00407248]
     :00401EC4 68F0274000              push 004027F0
     :00401EC9 6A00                    push 00000000
     :00401ECB 6A6F                    push 0000006F
     :00401ECD 50                      push eax

     * Reference To: USER32.DialogBoxParamA, Ord:008Ah
                                       |
     :00401ECE FF1510934000            Call dword ptr [00409310]
     :00401ED4 83F8FF                  cmp eax, FFFFFFFF
     :00401ED7 A148724000              mov eax, dword ptr [00407248]
     :00401EDC 7508                    jne 00401EE6
     :00401EDE 33C0                    xor eax, eax
     :00401EE0 C3                      ret

     The nag-screen appears at address :00401ECE. If we look some lines above, we see a 
     conditonal jump that leads to somewhere beyond the nag-screen. Could this be the jump we are
     searching for ? Yes, it is. I tested it with breakpointing at the jump and running the 
     program. When the jump is reached, I change the status of the zero-flag. (The jump is jne, 
     so the condition is the status of the zero-flag.) When we now push the "Run" button, the
     program starts without nag-screen :) To make this permanent, we open the file in a hex-
     editor and change the jump at offset 12BBh and 12BC (look at the statusbar of the W32Dasm 
     window) from 7524 (jne 00401EE1) to EB24 (jmp 00401EE1). Now the nag-screen will never 
     appear again.
     The next problem: Start Clean still says "Shareware Version". So we search for "Shareware"
     in W32Dasm. Sadly, we don't find anything like that, but we find "Registered to:". That will
     be the string that appears in the registered version instead "Shareware Version". Ok, we
     should see this:

     * Referenced by a CALL at Address:
     |:00401F07   
     |
     :004013C0 81EC10030000            sub esp, 00000310
     :004013C6 A064624000              mov al, byte ptr [00406264]
     :004013CB B93F000000              mov ecx, 0000003F
     :004013D0 56                      push esi
     :004013D1 88442410                mov byte ptr [esp+10], al
     :004013D5 57                      push edi
     :004013D6 8D7C2415                lea edi, dword ptr [esp+15]
     :004013DA 33C0                    xor eax, eax
     :004013DC F3                      repz
     :004013DD AB                      stosd
     :004013DE 66AB                    stosw
     :004013E0 AA                      stosb
     :004013E1 A064624000              mov al, byte ptr [00406264]
     :004013E6 8DBC2415010000          lea edi, dword ptr [esp+00000115]
     :004013ED B93F000000              mov ecx, 0000003F
     :004013F2 88842414010000          mov byte ptr [esp+00000114], al
     :004013F9 33C0                    xor eax, eax
     :004013FB F3                      repz
     :004013FC AB                      stosd
     :004013FD 66AB                    stosw

     * Possible StringData Ref from Data Obj ->"Software\Start Clean\Configuration"
                                       |
     :004013FF BE40624000              mov esi, 00406240
     :00401404 B908000000              mov ecx, 00000008
     :00401409 AA                      stosb
     :0040140A 8DBC2414020000          lea edi, dword ptr [esp+00000214]
     :00401411 F3                      repz
     :00401412 A5                      movsd 
     :00401413 66A5                    movsw
     :00401415 A4                      movsb
     :00401416 8DBC2437020000          lea edi, dword ptr [esp+00000237]
     :0040141D B938000000              mov ecx, 00000038
     :00401422 F3                      repz
     :00401423 AB                      stosd
     :00401424 8D4C2414                lea ecx, dword ptr [esp+14]
     :00401428 6864624000              push 00406264
     :0040142D AA                      stosb
     :0040142E 51                      push ecx

     * Reference To: USER32.wsprintfA, Ord:0249h
                                       |
     :0040142F 8B35D4924000            mov esi, dword ptr [004092D4]
     :00401435 C744241404010000        mov [esp+14], 00000104
     :0040143D FFD6                    call esi
     :0040143F 8D4C2410                lea ecx, dword ptr [esp+10]
     :00401443 8D84241C020000          lea eax, dword ptr [esp+0000021C]
     :0040144A 83C408                  add esp, 00000008
     :0040144D 51                      push ecx
     :0040144E 50                      push eax
     :0040144F 6801000080              push 80000001

     * Reference To: ADVAPI32.RegOpenKeyA, Ord:00D8h
                                       |
     :00401454 FF15F8914000            Call dword ptr [004091F8]
     :0040145A 8D4C240C                lea ecx, dword ptr [esp+0C]
     :0040145E 8D542414                lea edx, dword ptr [esp+14]
     :00401462 8D442410                lea eax, dword ptr [esp+10]
     :00401466 51                      push ecx
     :00401467 8B4C240C                mov ecx, dword ptr [esp+0C]
     :0040146B 52                      push edx
     :0040146C 50                      push eax
     :0040146D 6A00                    push 00000000

     * Possible StringData Ref from Data Obj ->"Name"
                                       |
     :0040146F 6838624000              push 00406238
     :00401474 51                      push ecx

     * Reference To: ADVAPI32.RegQueryValueExA, Ord:00E1h
                                       |
     :00401475 FF15F4914000            Call dword ptr [004091F4]
     :0040147B 8B4C2408                mov ecx, dword ptr [esp+08]
     :0040147F 51                      push ecx

     * Reference To: ADVAPI32.RegCloseKey, Ord:00C2h
                                       |
     :00401480 FF15F0914000            Call dword ptr [004091F0]
     :00401486 8D4C2414                lea ecx, dword ptr [esp+14]
     :0040148A 8D942414010000          lea edx, dword ptr [esp+00000114]
     :00401491 51                      push ecx

     * Possible StringData Ref from Data Obj ->"Registered to %s"
                                       |
     :00401492 6878624000              push 00406278
     :00401497 52                      push edx
     :00401498 FFD6                    call esi
     :0040149A 8D8C2420010000          lea ecx, dword ptr [esp+00000120]
     :004014A1 8B942428030000          mov edx, dword ptr [esp+00000328]
     :004014A8 83C40C                  add esp, 0000000C

     Pretty long code snippet, isn't it ;-) What should we see here ? EVERYTHING. This snippet
     is called from location :00401F07, as you can see in the second line. The name is stored
     in Software\Start Clean\Configuration\Name what is a Windows Registry key. So fire up
     the Registry and enter something there. Ok, now we have to look at :00401F07

     * Reference To: USER32.CreateDialogParamA, Ord:0048h
                                       |
     :00401EF2 FF1514934000            Call dword ptr [00409314]
     :00401EF8 833D4C72400000          cmp dword ptr [0040724C], 00000000
     :00401EFF A384734000              mov dword ptr [00407384], eax
     :00401F04 7409                    je 00401F0F 
     :00401F06 50                      push eax
     :00401F07 E8B4F4FFFF              call 004013C0
     :00401F0C 83C404                  add esp, 00000004

     We see a conditional jump in front of our call. When we set a breapoint on it and step 
     through the code, we see that the jump condition is met when we have a unregistered version.
     of Start Clean. When we change the zero flag status (remember: je has same condition as jne)
     the call is executed and we see "Registered to: your-name" in the window :) To make this
     permanent, we open the file in a hex-editor and change the 7409 (je...) at offset 1305h
     in 9090 (do nothing).
     For those guys that don't like no-oping:
     Change the cmp dword ptr [0040724C], 00000000
     to         cmp dword ptr [0040724C], 00000002
     DON'T      cmp dword ptr [0040724C], 00000001 , because that is the flag "Registered" and
     the Shareware string would appear again, when we register Start Clean correctly.

     That's all for the Disassembler part, now go to the Debugger part.


     IV. Cracking with a Debugger (Soft-Ice for Windows/W32Dasm)
    
     IV.1. Installing Soft-Ice
     Having installed Soft-Ice. There are several difficulties to master. First you have to load
     Soft-Ice before you start Windows, second you have to choose your graphics driver and third
     you have to edit the file 'Winice.dat' in the Soft-Ice directory.
     For the first difficulty, I would install a software-bootmenu in the autoexec.bat and
     config.sys file.
     Example:
     @Echo Off

     AUTOEXEC.BAT:
 
     REM Here put in your normal stuff, like drivers

     :SICE
     C:\SIW95\WINICE.EXE
     goto common
     :NORM
     goto common
     :common
     End of file
 
     The lines starting with ':' are places to jump to, when a .
     The 'goto'-line are the jumps.

     CONFIG.SYS
     
     [menu]
     menuitem SICE,Soft-Ice
     menuitem NORM,Normal Mode
     menudefault NORM,5

     [SICE]
     [NORM]
     [common]
    
     Put your normal stuff here.

     End of File

     Next difficulty: Start VSetup in the SI directory (Soft-Ice=SICE=SI). If your video-card
     isn't mentioned here choose VGA, because SI won't work when you choose different. If you 
     need to choose VGA you need a hardware-bootmenu, too, because you have to switch between 
     the video drivers when you start Windows in normal mode or in SI-Node. You can do this in 
     the Windows Control Panel/System. Copy your hardware profile and disable your video card in
     the new profile. Save. Next time you start windows you can choose the hardware and the 
     software you wish to load. If you disabled your video card and you start Windows-SI there 
     are some error messages to choose graphic drivers. Just [ESC] them away.

     Third difficulty:
     No real difficulty. Load the file winice.dat in a text-editor and remove the ; from the 
     lines
     ;exp=c:\windows\system\kernel32.dll
     ;exp=c:\windows\system\user32.dll
     ;exp=c:\windows\system\gdi32.dll

     standing below the lines
     ; ***** Examples of export symbols that can be included for Chicago *****
     ; Change the path to the appropriate drive and directory

     IV.2 Let's start cracking
     Now restart your computer with the SI-Configuration. In Windows press [CTRL]+[D] to see if
     you can load SI. If nothing happens, you forgot to load SI in your Autoexec.bat, if the
     screen is black, and you have already chosen video drivers, you have a little problem.
     Try to fix it with the help of the WWW.

     I will crack with W32Dasm debug mode, because I am on holidays and forgot SICE :(.
     But that doesn't matter it is the same.
     If you try to register Start Clean, a message "Incorrect Code" should appear. Search for
     this string in your W32Dasm deadlisting. You should see this:
     
     * Referenced by a (U)nconditional or (C)onditional Jump at Address:
     |:004027A3(C)
     |
     :004027C1 6A00                    push 00000000
     :004027C3 6A00                    push 00000000

     * Possible StringData Ref from Data Obj ->"Incorrect code!"
                                  |
     :004027C5 68AC634000              push 004063AC
     :004027CA 56                      push esi

     * Reference To: USER32.MessageBoxA, Ord:0188h
                                  |
     :004027CB FF1534934000            Call dword ptr [00409334]
     :004027D1 B801000000              mov eax, 00000001
     :004027D6 5E                      pop esi
     :004027D7 C21000                  ret 0010

     We quickly see, that this snippet is called (or this time better jumped) from :004027A3. So
     let's have a look at it.

     :00402794 8B742408                mov esi, dword ptr [esp+08]
     :00402798 56                      push esi
     :00402799 E8B2E9FFFF              call 00401150
     :0040279E 83C404                  add esp, 00000004
     :004027A1 85C0                    test eax, eax
     :004027A3 741C                    je 004027C1
     :004027A5 C7054C72400001000000    mov dword ptr [0040724C], 00000001
     :004027AF 6A01                    push 00000001
     :004027B1 56                      push esi

     * Reference To: USER32.EndDialog, Ord:00ADh
                                       | 
     :004027B2 FF153C934000            Call dword ptr [0040933C]
     :004027B8 B801000000              mov eax, 00000001
     :004027BD 5E                      pop esi 
     :004027BE C21000                  ret 0010

     We don't have to understand exactly what's going on: In the call at :00402799 the valid 
     serial is calculated and compared with our serial. The je at :004027A3 means: If the two
     serials are not the same, then jump, else "Thank you for registering". So we have to get the
     correct serial. Look what happens in the Call:

     * Referenced by a CALL at Address:
     |:00402799   
     |
     :00401150 81EC0C020000            sub esp, 0000020C
     :00401156 A064624000              mov al, byte ptr [00406264]
     :0040115B B93F000000              mov ecx, 0000003F
     :00401160 56                      push esi
     :00401161 8844240C                mov byte ptr [esp+0C], al 
     :00401165 57                      push edi
     :00401166 8D7C2411                lea edi, dword ptr [esp+11]
     :0040116A 33C0                    xor eax, eax
     :0040116C F3                      repz
     :0040116D AB                      stosd
     :0040116E 66AB                    stosw

     * Possible StringData Ref from Data Obj ->"Software\Start Clean\Configuration"
                                       |
     :00401170 BE40624000              mov esi, 00406240
     :00401175 B908000000              mov ecx, 00000008
     :0040117A AA                      stosb
     :0040117B 8DBC2410010000          lea edi, dword ptr [esp+00000110]
     :00401182 F3                      repz
     :00401183 A5                      movsd
     :00401184 66A5                    movsw
     :00401186 B938000000              mov ecx, 00000038
     :0040118B 6800010000              push 00000100
     :00401190 A4                      movsb
     :00401191 8DBC2437010000          lea edi, dword ptr [esp+00000137]
     :00401198 6830614000              push 00406130
     :0040119D F3                      repz
     :0040119E AB                      stosd
     :0040119F AA                      stosb
     :004011A0 8BBC2420020000          mov edi, dword ptr [esp+00000220]
     :004011A7 6805040000              push 00000405
     :004011AC 57                      push edi

     * Reference To: USER32.GetDlgItemTextA, Ord:00EDh
                                       |
     :004011AD 8B35D8924000            mov esi, dword ptr [004092D8]
     :004011B3 FFD6                    call esi
     :004011B5 8D442410                lea eax, dword ptr [esp+10]
     :004011B9 6800010000              push 00000100
     :004011BE 50                      push eax
     :004011BF 6806040000              push 00000406
     :004011C4 57                      push edi
     :004011C5 FFD6                    call esi
     :004011C7 6830604000              push 00406030
     :004011CC 6830614000              push 00406130
     :004011D1 E8AA000000              call 00401280
     :004011D6 8D442418                lea eax, dword ptr [esp+18]
     :004011DA 83C408                  add esp, 00000008
     :004011DD 50                      push eax
     :004011DE 6830604000              push 00406030
  
     * Reference To: KERNEL32.lstrcmpA, Ord:0269h
                                       |
     :004011E3 FF1520924000            Call dword ptr [00409220]
     :004011E9 85C0                    test eax, eax
     :004011EB 0F8580000000            jne 00401271
     :004011F1 8D44240C                lea eax, dword ptr [esp+0C]
     :004011F5 8D4C2408                lea ecx, dword ptr [esp+08]
     :004011F9 50                      push eax
     :004011FA 51                      push ecx
     :004011FB 8D942418010000          lea edx, dword ptr [esp+00000118]
     :00401202 6A00                    push 00000000
     :00401204 683F000F00              push 000F003F
     :00401209 6A00                    push 00000000

     Now it is indeed better to use W32Dasm. Just debug it with API details enabled. At :004011B3
     the name is taken from the input field, as you can easily see from the appearing window.
     At :004011C5 the entered serial is taken. Then a call follows (where the real serial is
     obviously calculated). At :004011E3 the length of two strings are compared. One of them
     is the serial, you entered, the other one is - you got it :) - the real serial. This time
     getting the serial with W32Dasm was indeed easier than getting it with SICE.
     To get it with SICE, you have to step one line beyond the calculation call and enter "d eax"
     because the valid serial is stored in eax in the call at :004011D1.

IV.  Writing a patch in C++
     You can easily write a patch for the nag-screen and the "Shareware" string. Here is the
     base for one in C++.

     FILE *handle;
     handle = fopen("Filename.exe", "r+b");
     if (handle==0)
     {
        cprintf("No File Filename.exe found");
     }
    
     else
     {
       fseek(handle, HERE OFFSET IN DECIMAL, SEEK_SET);
       fprintf(handle,"%c",HERE NEW VALUE IN DECIMAL);
       fclose(handle);
     }

V.   Writing a key generator
     This part is the main reason why I wrote this tutorial. In Quapla's tutorial, this part was
     missing although it is a good example for an easy (but not too easy) key generator for 
     newbies. When we enter the code calculation call at :004011D1 we see. I will comment 
     every that is important for a keygen.

     * Referenced by a CALL at Addresses:
     |:0040111F   , :004011D1   
     |
     :00401280 81EC00010000            sub esp, 00000100
     :00401286 A064624000              mov al, byte ptr [00406264]
     :0040128B 88442400                mov byte ptr [esp], al
     :0040128F 53                      push ebx
     :00401290 56                      push esi
     :00401291 33C0                    xor eax, eax
     :00401293 57                      push edi
     :00401294 B93F000000              mov ecx, 0000003F
     :00401299 8D7C240D                lea edi, dword ptr [esp+0D]
     :0040129D 55                      push ebp
     :0040129E F3                      repz
     :0040129F AB                      stosd
     :004012A0 66AB                    stosw
     :004012A2 BD6A000000              mov ebp, 0000006A    ;;EBP IS INITIALIZED WITH 6A = 106
     :004012A7 6864624000              push 00406264
     :004012AC AA                      stosb
     :004012AD 8BB4241C010000          mov esi, dword ptr [esp+0000011C]
     :004012B4 56                      push esi

     * Reference To: USER32.wsprintfA, Ord:0249h
                                       |
     :004012B5 FF15D4924000            Call dword ptr [004092D4]
     :004012BB 8B9C241C010000          mov ebx, dword ptr [esp+0000011C]
     :004012C2 83C408                  add esp, 00000008
     :004012C5 8BC3                    mov eax, ebx

     * Reference To: USER32.CharNextA, Ord:001Eh
                                       |
     :004012C7 8B3DDC924000            mov edi, dword ptr [004092DC]
     :004012CD 803B00                  cmp byte ptr [ebx], 00
     :004012D0 740F                    je 004012E1

     * Referenced by a (U)nconditional or (C)onditional Jump at Address:
     |:004012DF(C)
     |

     IN THIS LOOP (FROM 1 TO LENGTH(NAME)), THE FIRST PART IS CALCULATED

     :004012D2 0FBE08                  movsx ecx, byte ptr [eax]       ;; ECX = 1./2... CHAR
     :004012D5 50                      push eax
     :004012D6 8D6C4D00                lea ebp, dword ptr [ebp+2*ecx]  ;;EBP = EBP + (2 * ECX)
     :004012DA FFD7                    call edi
     :004012DC 803800                  cmp byte ptr [eax], 00          ;;WAS THAT THE LAST CHAR ?
     :004012DF 75F1                    jne 004012D2                    ;;IF NOT THEN LOOP

     END LOOP
     1. PART OF SERIAL = DECIMAL(EBP)
     
     * Referenced by a (U)nconditional or (C)onditional Jump at Address:
     |:004012D0(C)
     |
     :004012E1 8D442410                lea eax, dword ptr [esp+10]
     :004012E5 55                      push ebp

     * Possible StringData Ref from Data Obj ->"%d-"              ;; HERE YOU SEE THAT THE FIRST
                                                                  ;; PART IS DEC(EBP)-
                                  |
     :004012E6 6874624000              push 00406274
     :004012EB 50                      push eax

     * Reference To: USER32.wsprintfA, Ord:0249h
                                       |
     :004012EC FF15D4924000            Call dword ptr [004092D4]
     :004012F2 8D44241C                lea eax, dword ptr [esp+1C]
     :004012F6 83C40C                  add esp, 0000000C
     :004012F9 50                      push eax
     :004012FA 56                      push esi

     * Reference To: KERNEL32.lstrcatA, Ord:0266h
                                       |
     :004012FB FF153C924000            Call dword ptr [0040923C]
     :00401301 8BC3                    mov eax, ebx
     :00401303 803B00                  cmp byte ptr [ebx], 00
     :00401306 7412                    je 0040131A

     * Referenced by a (U)nconditional or (C)onditional Jump at Address:
     |:00401318(C)
     |

     IN THIS LOOP (FROM 1 TO LENGTH(NAME)), THE SECOND PART IS CALCULATED (EBP=still valid)

     :00401308 0FBE08                  movsx ecx, byte ptr [eax]        ;; ECX=1./2./3... char
     :0040130B 03C9                    add ecx, ecx                     ;; ECX is doubled
     :0040130D 50                      push eax
     :0040130E 8D14C9                  lea edx, dword ptr [ecx+8*ecx]   ;; EDX = 9*ECX
     :00401311 03EA                    add ebp, edx                     ;; EBP = EBP + EDX
     :00401313 FFD7                    call edi
     :00401315 803800                  cmp byte ptr [eax], 00           ;; LAST CHAR ?
     :00401318 75EE                    jne 00401308                     ;; NO THEN LOOP

     END LOOP
     2. PART OF SERIAL = DECIMAL(EBP) + "-"; SO WE HAVE PART1-PART2-

     * Referenced by a (U)nconditional or (C)onditional Jump at Address:
     |:00401306(C)
     |
     :0040131A 8D442410                lea eax, dword ptr [esp+10]
     :0040131E 55                      push ebp

     * Possible StringData Ref from Data Obj ->"%d-"
                                       |
     :0040131F 6874624000              push 00406274
     :00401324 50                      push eax

     * Reference To: USER32.wsprintfA, Ord:0249h
                                       |
     :00401325 FF15D4924000            Call dword ptr [004092D4]
     :0040132B 8D44241C                lea eax, dword ptr [esp+1C]
     :0040132F 83C40C                  add esp, 0000000C
     :00401332 50                      push eax
     :00401333 56                      push esi

     * Reference To: KERNEL32.lstrcatA, Ord:0266h
                                  |
     :00401334 FF153C924000            Call dword ptr [0040923C]
     :0040133A 8BC3                    mov eax, ebx
     :0040133C 803B00                  cmp byte ptr [ebx], 00
     :0040133F 7418                    je 00401359

     * Referenced by a (U)nconditional or (C)onditional Jump at Address:
     |:00401357(C)
     |

     IN THIS LOOP (FROM 1 TO LENGTH(NAME)), THE THIRD PART IS CALCULATED (EBP=still valid)

     :00401341 0FBE08                  movsx ecx, byte ptr [eax] ;; ECX = 1./2./3... CHAR
     :00401344 50                      push eax
     :00401345 8D2C89                  lea ebp, dword ptr [ecx+4*ecx]  ;; EBP = 5 * ECX
     :00401348 8D0C69                  lea ecx, dword ptr [ecx+2*ebp]  ;; ECX = ECX + (2 * EBP)
     :0040134B 8D2C4D01000000          lea ebp, dword ptr [2*ecx+00000001] ;; EBP = (2 * ECX) + 1
     :00401352 FFD7                    call edi
     :00401354 803800                  cmp byte ptr [eax], 00  ;; LAST CHAR ?
     :00401357 75E8                    jne 00401341            ;; IF NOT LOOP

     END LOOP
     3. PART OF SERIAL = DECIMAL(EBP) + "-"; SO WE HAVE PART1-PART2-PART3-

     * Referenced by a (U)nconditional or (C)onditional Jump at Address:
     |:0040133F(C)
     |
     :00401359 8D442410                lea eax, dword ptr [esp+10]
     :0040135D 55                      push ebp

     * Possible StringData Ref from Data Obj ->"%d-"
                                       |
     :0040135E 6874624000              push 00406274
     :00401363 50                      push eax

     * Reference To: USER32.wsprintfA, Ord:0249h
                                       |
     :00401364 FF15D4924000            Call dword ptr [004092D4]
     :0040136A 8D44241C                lea eax, dword ptr [esp+1C]
     :0040136E 83C40C                  add esp, 0000000C
     :00401371 50                      push eax
     :00401372 56                      push esi
 
     * Reference To: KERNEL32.lstrcatA, Ord:0266h
                                       |
     :00401373 FF153C924000            Call dword ptr [0040923C]
     :00401379 8BC3                    mov eax, ebx
     :0040137B 803B00                  cmp byte ptr [ebx], 00
     :0040137E 7412                    je 00401392

     * Referenced by a (U)nconditional or (C)onditional Jump at Address:
     |:00401390(C)
     |

     IN THIS LOOP (FROM 1 TO LENGTH(NAME)), THE LAST PART IS CALCULATED (EBP=still valid)

     :00401380 0FBE08                  movsx ecx, byte ptr [eax]  ;; ECX = 1./2./3... CHAR
     :00401383 50                      push eax
     :00401384 8D2C8D1D000000          lea ebp, dword ptr [4*ecx+0000001D] ;;EBP = (4 * ECX) + 29
     :0040138B FFD7                    call edi
     :0040138D 803800                  cmp byte ptr [eax], 00  ;; LAST CHAR ? 
     :00401390 75EE                    jne 00401380            ;; IF NOT LOOP

     END LOOP
     4. PART OF SERIAL = DECIMAL(EBP); SO WE HAVE PART1-PART2-PART3-PART4

     * Referenced by a (U)nconditional or (C)onditional Jump at Address:
     |:0040137E(C)
     |
     :00401392 8D442410                lea eax, dword ptr [esp+10]
     :00401396 55                      push ebp

     * Possible StringData Ref from Data Obj ->"%d"
                                       |
     :00401397 6870624000              push 00406270
     :0040139C 50                      push eax

     * Reference To: USER32.wsprintfA, Ord:0249h
                                  |
     :0040139D FF15D4924000            Call dword ptr [004092D4]
     :004013A3 8D44241C                lea eax, dword ptr [esp+1C]
     :004013A7 83C40C                  add esp, 0000000C
     :004013AA 50                      push eax
     :004013AB 56                      push esi

     * Reference To: KERNEL32.lstrcatA, Ord:0266h
                                       |
     :004013AC FF153C924000            Call dword ptr [0040923C]
     :004013B2 5D                      pop ebp
     :004013B3 5F                      pop edi
     :004013B4 5E                      pop esi
     :004013B5 5B                      pop ebx
     :004013B6 81C400010000            add esp, 00000100
     :004013BC C3                      ret

     Now you should be able to write a keygen. The source for mine (C++ Builder) is:
     Edit1 is the name, Edit2 the serial.

     int ebp;
     int ecx;
     String serial;
     ebp=106;
     for (int i=1;i<Edit1->Text.Length()+1;i++)
     {
       ecx = Edit1->Text[i];
       ebp = ebp + (2*ecx);
     }

     serial = IntToStr(ebp)+"-";
 
     for (int i=1;i<Edit1->Text.Length()+1;i++)
     {
       ecx = Edit1->Text[i];
       ecx = ecx * 2;
       ebp = ebp + (9*ecx);
     }

     serial = serial + IntToStr(ebp)+"-";

     for (int i=1;i<Edit1->Text.Length()+1;i++)
     {
       ecx = Edit1->Text[i];
       ebp=ecx*5;
       ecx = ecx + (2 * ebp);
       ebp = (2*ecx)+1;
     }

     serial = serial + IntToStr(ebp)+"-";

     for (int i=1;i<Edit1->Text.Length()+1;i++)
     {
       ecx = Edit1->Text[i];
       ebp=(4*ecx)+29;
     }

     serial = serial + IntToStr(ebp);

     Edit2->Text=serial;

VI.  BTW
     Hope my tutorial was helpful for you and see you again in my next tutorial. 
     
     Greets to: Fravia+, tKC, ED!SON, Moral Insanity, The Sandman, Eternal Bliss, DaVinci and 
     all [hf] members

     All Tutorials by LaZaRuS [hf]
       
#|  date  |   name           |version|W32Dasm|Soft-Ice|kind of crack            |
-|--------|------------------|-------|-------|--------|-------------------------|
1|20.01.99|Jaylock           |1,0,0,1|  (X)  |   (X)  |serial#                  |
2|31.01.99|Goldwave          |4.02   |  (X)  |   (X)  |serial#,nag-screens      |
3|28.03.99|AxMan             |3.00   |  (X)  |   (X)  |serial#,remove date-limit|
4|29.03.99|C++Builder Strings|       |  (X)  |   (X)  |how to find strings in   |
 |        |                  |       |       |        |C++ Builder that are not |
 |        |                  |       |       |        |hardcoded                |
5|29.03.99|Better Protection |       |       |        |How to protect shareware |
 |        |                  |       |       |        |better against crackers  |
6|04.04.99|Start Clean       |1.2    |  (X)  |   (X)  |nag-screen/serial/keygen |

     
LaZaRuS [hf]
Visit Hellforge at http://members.xoom.com/hell_crack for more tutorials and high quality
cracking links.
If you want to mail me: lazarus666@gnwmail.com